package com.trip.api;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import com.trip.config.AppUser;
import com.trip.config.CommonProperties;
import com.trip.dao.tables.pojos.PicDomain;
import com.trip.dao.tables.pojos.PlanDiscussionDomain;
import com.trip.dao.tables.pojos.PlanItemDetailLikeDomain;
import com.trip.dao.tables.pojos.TripPlanDomain;
import com.trip.dao.tables.pojos.TripPlanItemDetailDomain;
import com.trip.exception.ServiceException;
import com.trip.service.PicService;
import com.trip.service.TripPlanService;
import com.trip.util.AuthUtil;
import com.trip.vo.*;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * Created by hc24 on 2017/10/7.
 */
@AppUser
@Validated
@RestController
@RequestMapping("plan")
public class TripPlanController {

    private static final Logger logger= LoggerFactory.getLogger(TripPlanController.class);

    @Autowired
    private PicService picService;

    @Autowired
    private TripPlanService tripPlanService;

    @Autowired
    private CommonProperties properties;

    @ApiOperation("Upload plan cover")
    @RequestMapping(value = "/cover",method = RequestMethod.POST)
    public ControllerResult<PicDomain> uploadCover(@RequestHeader(required = false) @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                   @NotNull MultipartFile cover){
        logger.info("receive file:"+cover.getOriginalFilename());
        properties.validatePic(cover);

        try {
            PicDomain coverPic= picService.savePic(cover.getBytes(),cover.getOriginalFilename().substring(cover.getOriginalFilename().indexOf(".")),3);
            return ControllerResult.success(coverPic);
        } catch (IOException e) {
            throw new ServiceException("IO error,please retry");
        }
    }

    @ApiOperation("Create new plan")
    @RequestMapping(value = "",method = RequestMethod.POST)
    public ControllerResult<TripPlanDomain> createPlan(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                       @RequestBody @Valid TripPlanRequest tripPlanRequest){
        tripPlanRequest.setCreatedBy(AuthUtil.getUserId(authToken));
        return ControllerResult.success(tripPlanService.save(tripPlanRequest));
    }

    @ApiOperation("Update plan")
    @PostMapping("/{planId}")
    public ControllerResult<TripPlanDomain> updatePlan(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token")String authToken,
                                                       @RequestBody @Valid TripPlanRequest tripPlanRequest,@PathVariable Integer planId){
        return ControllerResult.success(tripPlanService.update(planId, tripPlanRequest));
    }

    @ApiOperation("Query partner")
    @GetMapping(value = "/{planId}/partner")
    public ControllerResult<List<UserSimpleVo>> queryPartners(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                              @PathVariable Integer planId){
        return ControllerResult.success(tripPlanService.queryPartner(planId));
    }

    @ApiOperation("Add partner")
    @PostMapping(value = "/{planId}/partner")
    public ControllerResult addPartners(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                        @PathVariable Integer planId,@RequestBody SingleVo<Set<Integer>> partnerSet){
        tripPlanService.addPartner(planId,partnerSet.getValue());
        return ControllerResult.success();
    }

    @ApiOperation("Delete partner")
    @DeleteMapping(value = "/{planId}/partner/{partnerId}")
    public ControllerResult deletePartners(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                        @PathVariable Integer planId,@PathVariable Integer partnerId){
        Set<Integer> partnerSet=new HashSet<>();
        partnerSet.add(partnerId);
        tripPlanService.deletePartner(planId,partnerSet);
        return ControllerResult.success();
    }

    @ApiOperation("Trip planer index")
    @RequestMapping(value = "",method = RequestMethod.GET)
    public ControllerResult<Map<String,List<TripPlanDomain>>> queryTripPlanList(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken){
        Integer userId=AuthUtil.getUserId(authToken);
        Map<String,List<TripPlanDomain>> resultMap=new HashMap<>();
        resultMap.put("past",tripPlanService.queryPastList(userId));
        resultMap.put("future",tripPlanService.queryFutureList(userId));

        return ControllerResult.success(resultMap);
    }
    @ApiOperation("Delete plan")
    @RequestMapping(value = "/{planId}",method = RequestMethod.DELETE)
    public ControllerResult deletePlan(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                       @PathVariable Integer planId){
        tripPlanService.delete(planId,AuthUtil.getUserId(authToken));
        return ControllerResult.success();
    }


    @ApiOperation("Get plan items")
    @RequestMapping(value = "/item",method = RequestMethod.GET)
    public ControllerResult<List<TripPlanItemVo>> queryItemList(@RequestHeader(required = false) @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                                    @NotNull @RequestParam Integer planId){
        return ControllerResult.success(tripPlanService.queryItemList(planId));
    }

    @ApiOperation("Get plan discussion")
    @RequestMapping(value = "{planId}/discussion",method = RequestMethod.GET)
    public ControllerResult<List<DiscussionVo>> queryDiscussionList(@RequestHeader(required = false) @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                                    @NotNull @PathVariable Integer planId){
        return ControllerResult.success(tripPlanService.queryDiscussionList(planId));
    }

    @ApiOperation("Get Item Detail")
    @GetMapping("/item/{itemId}/detail")
    public ControllerResult<List<TripPlanItemDetailVo>> queryItemDetail(@RequestHeader(required = false) @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                                        @NotNull @PathVariable Integer itemId){
        return ControllerResult.success(tripPlanService.queryItemDetailList(itemId,AuthUtil.getUserId(authToken)));
    }

    @ApiOperation("Add Place or Experience to plan")
    @RequestMapping(value = "/item/detail",method = RequestMethod.POST)
    public ControllerResult<List<TripPlanItemDetailDomain>> addItemDetail(@RequestHeader(required = false) @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                                          @RequestBody @Valid ItemDetailRequest request){
        return ControllerResult.success(tripPlanService.addItemDetail(request.getItemId(),request.getPaeIds()));
    }

    @ApiOperation("Delete Place or Experience in plan")
    @RequestMapping(value = "/item/detail/{detailId}",method = RequestMethod.DELETE)
    public ControllerResult deleteItemDetail(@RequestHeader(required = false) @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                                          @PathVariable Integer detailId){
        tripPlanService.deleteItemDetail(detailId);
        return ControllerResult.success();
    }

    @ApiOperation("Sort item detail")
    @PostMapping("/item/detail/seq")
    public ControllerResult sortItemDetail(@RequestHeader(required = false) @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                           @RequestBody SingleVo<List<Integer>> detailSet){
        tripPlanService.sortItemDetail(detailSet.getValue());
        return ControllerResult.success();
    }

    @ApiOperation("Move item detail")
    @PostMapping("/item/detail/{detailId}/{toItemId}")
    public ControllerResult moveItemDetail(@RequestHeader(required = false) @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                           @PathVariable Integer detailId,@PathVariable Integer toItemId){
        tripPlanService.moveItemDetail(detailId,toItemId);
        return ControllerResult.success();
    }

    @ApiOperation("Submit discussion")
    @RequestMapping(value = "{planId}/discussion",method = RequestMethod.POST)
    public ControllerResult<PlanDiscussionDomain> addDiscussion(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                                @PathVariable Integer planId, @Valid @RequestBody DiscussionRequest request){
        PlanDiscussionDomain domain=new PlanDiscussionDomain();
        BeanUtils.copyProperties(request,domain);
        domain.setUserId(AuthUtil.getUserId(authToken));
        domain.setCreatedAt(LocalDateTime.now());
        domain.setPlanId(planId);
        return ControllerResult.success(tripPlanService.addDiscussion(domain));
    }

    @ApiOperation("Add discussion image")
    @RequestMapping(value = "{planId}/discussion/pic",method = RequestMethod.POST)
    public ControllerResult<PlanPicDiscussionVo> addDiscussion(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                               @PathVariable Integer planId, @NotNull MultipartFile pic){
        logger.info("receive file:"+pic.getOriginalFilename());
        properties.validatePic(pic);

        try {
            PicDomain picDomain= picService.savePic(pic.getBytes(),pic.getOriginalFilename().substring(pic.getOriginalFilename().indexOf(".")),3);
            PlanDiscussionDomain domain=new PlanDiscussionDomain();
            domain.setUserId(AuthUtil.getUserId(authToken));
            domain.setCreatedAt(LocalDateTime.now());
            domain.setPicId(picDomain.getId());
            domain.setPlanId(planId);
            domain.setType(2);
            domain= tripPlanService.addDiscussion(domain);

            PlanPicDiscussionVo vo=new PlanPicDiscussionVo();
            BeanUtils.copyProperties(domain,vo);
            vo.setHeight(picDomain.getHeight());
            vo.setWidth(picDomain.getWidth());

            return ControllerResult.success(vo);
        } catch (IOException e) {
            throw new ServiceException("IO error,please retry");
        }
    }

    @ApiOperation("Query user like list")
    @RequestMapping(value = "/item/detail/{detailId}/like",method = RequestMethod.GET)
    public ControllerResult<LikedVo> queryLikedUser(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
            @PathVariable Integer detailId){
        Integer selfId=AuthUtil.getUserId(authToken);
        LikedVo likedVo=new LikedVo();
        likedVo.setLiked(tripPlanService.queryLike(detailId,selfId)==null?false:true);
        likedVo.setLikedList(tripPlanService.queryLikeList(detailId));

        return ControllerResult.success(likedVo);
    }

    @ApiOperation("Like item detail")
    @RequestMapping(value = "/item/detail/{detailId}/like",method = RequestMethod.POST)
    public ControllerResult<PlanItemDetailLikeDomain> like(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                @PathVariable Integer detailId){
        return ControllerResult.success(tripPlanService.like(detailId,AuthUtil.getUserId(authToken)));
    }

    @ApiOperation("Cancel like item detail")
    @RequestMapping(value = "/item/detail/{detailId}/like",method = RequestMethod.DELETE)
    public ControllerResult cancelLike(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                 @PathVariable Integer detailId){
        tripPlanService.cancelLike(detailId,AuthUtil.getUserId(authToken));
        return ControllerResult.success();
    }

    @ApiOperation("Unread discussion count")
    @GetMapping("/discussion/unread")
    public ControllerResult<List<PlanDiscussionCountVo>> unreadDiscussionCount(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken
                                                           ){
        return ControllerResult.success(tripPlanService.unreadDiscussionCount(AuthUtil.getUserId(authToken)));
    }

    @ApiOperation("Unread discussion count")
    @PostMapping("/{planId}/discussion/setRead")
    public ControllerResult setDiscussionReaded(@RequestHeader @ApiParam(name = "authToken", value = "Auth Token",required = true)String authToken,
                                                           @PathVariable Integer planId,@RequestBody SingleVo<List<Integer>> discussionIds){
        tripPlanService.setDiscussionReaded(planId,discussionIds.getValue(),AuthUtil.getUserId(authToken));
        return ControllerResult.success();
    }

    static class LikedVo{
        private Boolean liked;
        private List<LikeUserVo> likedList;

        public Boolean getLiked() {
            return liked;
        }

        public void setLiked(Boolean liked) {
            this.liked = liked;
        }

        public List<LikeUserVo> getLikedList() {
            return likedList;
        }

        public void setLikedList(List<LikeUserVo> likedList) {
            this.likedList = likedList;
        }
    }

    @Getter
    @Setter
    static class DiscussionRequest{
        @NotNull
        @ApiModelProperty(notes = "1:text;2:pic;3:pae")
        private Integer       type;
        private String       paeId;
        private String       picId;
        private String        messageText;


    }

    static class ItemDetailRequest{
        @NotNull
        private Integer itemId;
        @NotNull
        private String[] paeIds;

        public Integer getItemId() {
            return itemId;
        }

        public void setItemId(Integer itemId) {
            this.itemId = itemId;
        }

        public String[] getPaeIds() {
            return paeIds;
        }

        public void setPaeIds(String[] paeIds) {
            this.paeIds = paeIds;
        }
    }
}
